package io.openkunlun.javadsl;

import java.util.Map;
import java.util.function.BiConsumer;

public interface Tracer<I, O> {

    @SuppressWarnings("rawtypes")
    Tracer NOOP = new Tracer<Object, Object>() {
    };

    /**
     * @param context
     * @param carrier
     */
    default void extract(Context context, Iterable<Map.Entry<String, String>> carrier) {
    }

    /**
     * @param context
     * @param carrier
     */
    default void inject(Context context, BiConsumer<String, String> carrier) {
    }

    /**
     * Signal a request has been received and will be processed.
     *
     * @param context   the context data attached to the request
     * @param kind      the span kind
     * @param policy    the policy to apply
     * @param request   the request object
     * @param operation the request operation
     * @param headers   a read-only view of the request headers
     * @param tagExtractor the request tag extractor
     * @return the request trace
     */
    default <R> I receiveRequest(Context context,
                                 TracingKind kind,
                                 TracingPolicy policy,
                                 R request,
                                 String operation,
                                 Iterable<Map.Entry<String, String>> headers,
                                 TagExtractor<R> tagExtractor) {
        return null;
    }

    /**
     * Signal the response is sent.
     *
     * @param context  the context data attached to the request
     * @param response the response sent
     * @param payload  the payload returned by {@link #receiveRequest}
     * @param failure  the failure when not {@code null}
     * @param tagExtractor the response tag extractor
     */
    default <R> void sendResponse(Context context,
                                  R response,
                                  I payload,
                                  Throwable failure,
                                  TagExtractor<R> tagExtractor) {
    }

    /**
     * Signal a request is sent.
     *
     * <p> When the method returns {@code null}, no propagation happens and the client
     * shall not call {@link #receiveResponse}.
     *
     * @param context      the context data attached to the request
     * @param kind         the span kind
     * @param policy       the policy to apply
     * @param request      the request object
     * @param operation    the request operation
     * @param headers      a write only-view of the request headers
     * @param tagExtractor the request tag extractor
     * @return the request trace
     */
    default <R> O sendRequest(Context context,
                              TracingKind kind,
                              TracingPolicy policy,
                              R request,
                              String operation,
                              BiConsumer<String, String> headers,
                              TagExtractor<R> tagExtractor) {
        return null;
    }

    /**
     * Signal a response has been received.
     *
     * @param context  the context data attached to the request
     * @param response the response sent
     * @param payload  the payload returned by {@link #sendRequest}
     * @param failure  the failure when not {@code null}
     * @param tagExtractor the response tag extractor
     */
    default <R> void receiveResponse(Context context,
                                     R response,
                                     O payload,
                                     Throwable failure,
                                     TagExtractor<R> tagExtractor) {
    }
}
